package com.example.mybatis.service;

import com.example.common.pojo.MyEntity;
import com.example.common.service.TestService;
import com.example.mybatis.datasource.MyDataSourceStore;
import com.example.mybatis.datasource.RoutingDataSourceHolder;
import com.example.mybatis.mapper.StudentDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcOperations;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionOperations;
import org.springframework.web.bind.annotation.PathVariable;

import java.util.*;

/**
 * @author zty
 * @apiNote
 * @project_name mybatis-demo
 * @user tain
 * @create_at 2023/6/23 5:37
 * @create_vio IntelliJ IDEA
 */
@Service
public class MybatisTestService implements TestService {

    private final StudentDao studentDao;

    private final JdbcOperations jdbcOperations;

    private final RoutingDataSourceHolder routingDataSourceHolder;

    private final TransactionOperations transactionOperations;

    @Autowired
    public MybatisTestService(StudentDao studentDao, JdbcOperations jdbcOperations,
                              RoutingDataSourceHolder routingDataSourceHolder, TransactionOperations transactionOperations) {
        this.studentDao = studentDao;
        this.jdbcOperations = jdbcOperations;
        this.routingDataSourceHolder = routingDataSourceHolder;
        this.transactionOperations = transactionOperations;
    }

    @Override
    public Object doTest(Object param) {
        operateWithXA();
        return null;
    }

    private void selectOneByInjected() {
        studentDao.selectOneByInjected("远山 诗音' -- ");
    }

    /**
     * Transactional并不支持跨数据源事务！
     * 需要 AtomikosDataSourceBean 自 JTA依赖
     */
    @Transactional(rollbackFor = Exception.class)
    public void operateWithXA(){
        JdbcOperations jdbcOperations1 = new JdbcTemplate(MyDataSourceStore.getFirst());
        JdbcOperations jdbcOperations2 = new JdbcTemplate(MyDataSourceStore.getSecond());
        jdbcOperations1.update("delete from my_entity");
        jdbcOperations2.update("delete from my_entity");
        throw new RuntimeException("1111");
    }

    /**
     * Spring事务是如何知道mybatis对数据库做了什么操作的？
     * jdbc? 因为mybatis最终也是通过jdbc操作数据库的。
     * <p>
     *     {@link org.springframework.jdbc.datasource.DataSourceTransactionManager}
     * </p>
     */
    private void operateMultiByTransactionalOperations() {
        transactionOperations.execute(status -> operateMulti());
    }

    @Transactional(rollbackFor = Exception.class)
    public MyEntity operateMultiByAnnoTransactional() {
        return operateMulti();
    }

    private MyEntity operateMulti() {
        long studentId = 1;
        MyEntity myEntity = new MyEntity();
        myEntity.setId(studentId);
        myEntity.setStudentName("照尼马");
        myEntity.setAge((short)3);
        studentDao.deleteByPrimaryKey(studentId);
        studentDao.insertSelective(myEntity);
        throw new RuntimeException("");
    }

    private MyEntity getByMybatisDynamic(){
        return studentDao.selectByPrimaryKeyDynamic(1L);
    }

    private MyEntity getByMybatis(@PathVariable Long id) {
        long studentId = 1;
        MyEntity myEntity = new MyEntity();
        myEntity.setId(studentId);
        myEntity.setStudentName("远山 诗音");
        myEntity.setAge((short)17);
        studentDao.deleteByPrimaryKey(studentId);
        studentDao.insertSelective(myEntity);
        return studentDao.selectByPrimaryKey(studentId);
    }

    private List<MyEntity> list(){
        return studentDao.selectList();
    }

    private Object getWithJDBC(){
        return jdbcOperations.queryForList("select * from my_entity");
    }

    private String showDataBaseName(String dataSourceName){
        Set<String> allLookupKey = routingDataSourceHolder.showAllLookupKeys();
        Object currentLookupKey = routingDataSourceHolder.showCurrentLookupKey();
        Optional<String> optional = allLookupKey.stream().findAny();
        routingDataSourceHolder.determineCurrentDataSource(optional.orElse(null));
        currentLookupKey = routingDataSourceHolder.showCurrentLookupKey();
        List<Map<String, Object>> databases = jdbcOperations.queryForList("select database()");
        routingDataSourceHolder.reset();
        currentLookupKey = routingDataSourceHolder.showCurrentLookupKey();
        return Objects.toString(databases);
    }

}
